package ws.very.util.el
import ws.very.util.lang.ShortTypes._
import scala.reflect.ClassTag
import scala.util.Try
import scala.math.BigDecimal
object Els {
  trait Cond[In] extends Function1[In, B]
  case object FalseCond extends Cond[A] {
    def apply(in: A) = false
    override def toString = "false"
  }

  case class And[In](conds: Itb[Cond[In]]) extends Cond[In] {
    def apply(in: In) = conds.forall { _(in) }
    override def toString = conds.map { _.toString }.mkString(" && ")
  }
  case class Or[In](conds: Itb[Cond[In]]) extends Cond[In] {
    def apply(in: In) = conds.exists { _(in) }
    override def toString = conds.map { _.toString }.mkString(" || ")
  }

  trait WhenTypeCond[In, T] extends Cond[In] {
    def cond: Cond[T]
    def isType(in: In): Option[T]
    def apply(in: In) = isType(in).map { is => cond(is) }.getOrElse(false)
  }

  case class WhenStrThen[In](cond: Cond[S]) extends WhenTypeCond[In, S] {
    def isType(in: In) = Try { in.asInstanceOf[S] }.toOption
    override def toString = s"? whenStr then $cond"
  }

  case class WhenNumThen[In](cond: Cond[Number]) extends WhenTypeCond[In, Number] {
    def isType(in: In) = Try { in.asInstanceOf[Number] }.toOption
    override def toString = s"? whenNum then $cond"
  }
  case class Eq[In, W](value: W) extends Cond[In] {
    def apply(in: In) = in == value
    override def toString = s"? == $value"
  }

  object Str {
    trait CD extends Cond[S]
    case class StartsWith(value: S) extends CD {
      def apply(str: S) = str.startsWith(value)
      override def toString = s"? startsWith $value"
    }
  }

  object Num {
    trait CD extends Cond[Number]
    case class <(value: Number) extends CD {
      def apply(from: Number) = BigDecimal(from.toString) < BigDecimal(value.toString)
      override def toString = s"? < $value"
    }
    case class >(value: Number) extends CD {
      def apply(from: Number) = BigDecimal(from.toString) > BigDecimal(value.toString)
      override def toString = s"? > $value"
    }
  }

  //  case class Case[In,Out](cond: Cond[In], act: Action[Out])
  //  case class Match(cases: Itb[Case])

}

